package gatperdut.chato.core.threads;

import gatperdut.chato.constants.CSConstantsRandom;
import gatperdut.chato.constants.CSConstantsScores;
import gatperdut.chato.core.characters.BaseController;
import gatperdut.chato.core.characters.health.HealthController.LifeStatus;
import gatperdut.chato.model.Chato.Constant.Score;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class CombatThread extends Thread {

    public enum AttackResult {
        KILLED, DID_NOT_KILL, MISSED;
    };

    private final BaseController baseController;

    private BaseController target;

    private final List<BaseController> attackers = new ArrayList<BaseController>();

    private final Random random = new Random();

    public CombatThread( BaseController baseController, BaseController target ) {
        this.baseController = baseController;
        this.target = target;
    }

    @Override
    public void run() {
        while ( true ) {
            try {
                sleep( CSConstantsRandom.roll( getRandom(), 1, 7 ) * 1000 + 4000 );
            }
            catch ( InterruptedException e ) {
                getBaseController().getCombatController().setCombatThread( null );
                return;
            }
            if ( getTarget() != null ) {
                AttackResult ar = performAttack();
                if ( ar == AttackResult.KILLED ) {
                    getTarget().die( getBaseController() );
                    getBaseController().getCombatController().handleDeadTarget();
                }
                else {
                    getTarget().getCombatController().handleBecomingNonPacifist( getBaseController() );
                }
            }
        }
    }

    private AttackResult performAttack() {
        int attackRoll = CSConstantsRandom.roll( getRandom(), 1, 20 );
        int attackBonus = getBaseController().getCharacter().getAttackBonus();
        int strBonus = CSConstantsScores.getToHit( getBaseController().getScoresController().getScore( Score.STRENGTH ) );
        int armorClass = getTarget().getCharacter().getArmorClass();

        if ( attackRoll + attackBonus + strBonus > armorClass ) {
            getBaseController().getEchoes().txAttackMiss( getTarget() );
            return AttackResult.MISSED;
        }
        else {
            int dam = CSConstantsRandom.roll( getRandom(), 7, 14 );
            int damBonus = CSConstantsScores.getDam( getBaseController().getScoresController().getScore( Score.STRENGTH ) );
            int totalDam = dam + damBonus;
            LifeStatus lifeStatus = target.getHealthController().beHurt( totalDam );
            getBaseController().getEchoes().txAttackHit( getTarget(), totalDam );
            if ( lifeStatus == LifeStatus.DEAD ) {
                return AttackResult.KILLED;
            }
            else {
                return AttackResult.DID_NOT_KILL;
            }
        }
    }

    public void addAttacker( BaseController attacker ) {
        if ( getAttackers().contains( attacker ) ) {
            throw new IllegalStateException( "Adding an attacker twice to the set of attackers." );
        }

        getAttackers().add( attacker );
    }

    public void removeAttacker( BaseController attacker ) {
        if ( !getAttackers().contains( attacker ) ) {
            throw new IllegalStateException( "Removing a non-present attacker in the set of attackers." );
        }

        getAttackers().remove( attacker );
    }

    public String listAttackersShortDescription() {
        StringBuilder attackersStr = new StringBuilder( "" );
        boolean firstListed = false;
        int current = 0;
        for ( BaseController attacker : getAttackers() ) {
            current++;
            if ( !firstListed ) {
                firstListed = true;
            }
            else {
                if ( current == getAttackers().size() ) {
                    attackersStr.append( " and " );
                }
                else {
                    attackersStr.append( ", " );
                }
            }
            attackersStr.append( attacker.getCharacter().getShortDesc() );
        }
        return attackersStr.toString();
    }

    public BaseController getTarget() {
        return target;
    }

    public BaseController getBaseController() {
        return baseController;
    }

    public void setTarget( BaseController target ) {
        this.target = target;
    }

    public List<BaseController> getAttackers() {
        return attackers;
    }

    public Random getRandom() {
        return random;
    }
}
